package com.lace.waf.exception.handler;

import com.lace.waf.exception.BadRequestException;
import com.lace.waf.exception.ServiceException;
import com.lace.waf.exception.WafException;
import com.lace.waf.exception.errorCode.BaseCodeConfig;
import com.lace.waf.exception.entity.BaseResponseInfo;
import com.lace.waf.exception.entity.WebResponseInfo;
import com.lace.waf.response.RestWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJacksonValue;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.mvc.method.annotation.AbstractMappingJacksonResponseBodyAdvice;

import javax.servlet.http.HttpServletRequest;

@RestControllerAdvice
public class GlobalControllerAdvice extends AbstractMappingJacksonResponseBodyAdvice {

	private static final Logger logger = LoggerFactory.getLogger(GlobalControllerAdvice.class);

	/**
	 * 默认异常处理，返回500错误
	 */
	@ExceptionHandler(Exception.class)
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	public BaseResponseInfo defaultExceptionHandler(HttpServletRequest req, Exception e) {
		logger.error("error",e);
		return getExpResponse(req, BaseCodeConfig.E_1500, e.getClass().getName());
	}

	/**
	 * 默认异常处理，返回500错误
	 */
	@ExceptionHandler(RuntimeException.class)
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	public BaseResponseInfo runtimeExceptionHandler(HttpServletRequest req, RuntimeException e) {
		logger.error("error",e);
		return getExpResponse(req, BaseCodeConfig.E_1500, e.getClass().getName());
	}

	/**
	 * 业务层异常
	 */
	@ExceptionHandler(WafException.class)
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	public BaseResponseInfo ServiceExceptionHandler(HttpServletRequest req, WafException e) {
		logger.error("请求:{}，异常信息：{}", req.getRequestURL().toString(), e.getMsg());
		return getExpResponse(req, e.getCode(), e.getMsg());
	}

	/**
	 * 无法找到映射handler的异常处理，返回404错误
	 */
	@ExceptionHandler(NoHandlerFoundException.class)
	@ResponseStatus(HttpStatus.NOT_FOUND)
	public BaseResponseInfo NoHandlerFoundExceptionHandler(HttpServletRequest req, Exception e) {
		logger.error("请求:{}，异常信息：{}", req.getRequestURL().toString(), e.getMessage());
		return getExpResponse(req, BaseCodeConfig.E_1404, "系统找不到您要访问的服务");
	}

	/**
	 * 错误请求异常处理
	 */
	@ExceptionHandler(BadRequestException.class)
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	public BaseResponseInfo badRequestExceptionHandler(HttpServletRequest req, BadRequestException e) {
		logger.error("请求:{}，异常信息：{}", req.getRequestURL().toString(), e.getMsg());
		return getExpResponse(req, e.getCode(), e.getMsg());
	}

	/**
	 * 业务层异常
	 */
	@ExceptionHandler(ServiceException.class)
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	public BaseResponseInfo ServiceExceptionHandler(HttpServletRequest req, ServiceException e) {
		logger.error("请求:{}，异常信息：{}", req.getRequestURL().toString(), e.getMsg());
		return getExpResponse(req, e.getCode(), e.getMsg());
	}

	private BaseResponseInfo getExpResponse(HttpServletRequest req, String code, String msg) {
		return getBaseResponseInfo(req, false, code, msg, null);
	}

	/**
	 * 后处理，在方法有RestWrapper注解时，包装return type
	 */
	@Override
	protected void beforeBodyWriteInternal(MappingJacksonValue bodyContainer, MediaType contentType,
			MethodParameter returnType, ServerHttpRequest request, ServerHttpResponse response) {
		HttpServletRequest req = ((ServletServerHttpRequest)request).getServletRequest();
		Object rsp = bodyContainer.getValue();
		if(rsp instanceof BaseResponseInfo) {
			//pass
		} else if(rsp == null) {
			bodyContainer.setValue(getBaseResponseInfo(req, true, BaseCodeConfig.C_1000, "", bodyContainer.getValue()));
		} else {
			RestWrapper restWrapper =  returnType.getMethod().getAnnotation(RestWrapper.class);
			if(restWrapper != null) {
				bodyContainer.setValue(getBaseResponseInfo(req, true, restWrapper.code(), restWrapper.successMsg(), bodyContainer.getValue()));
			}
		}
	}

	private BaseResponseInfo getBaseResponseInfo(HttpServletRequest req,Boolean flag, String code, String msg, Object data) {
		WebResponseInfo rs = new WebResponseInfo();
		rs.setSuccess(flag);
		rs.setContent(data);
		rs.setUrl(req.getRequestURI());
		rs.setCode(code);
		rs.setMsg(msg);
		rs.setTimestamp(System.currentTimeMillis());

		return rs;
	}

}
